#include "uart.h"
#include "board.h"
uartStruct_t devUART6;
static uint8_t buffer[UART6_BUF_SIZE] = {0};
static uint8_t *pbuffer = NULL;
static uint16_t recvLength = 0;

static void UART6_SendBytes(uint8_t *pBuf, uint32_t length);
static void UART6_PrintString(const char *fmt, ...);
static uint16_t UART6_ReadBytes(uint8_t *pBuf);
void USART6_Init(uint32_t BaudRate) {
	LL_RCC_ClocksTypeDef rcc_clocks;
	/* (1) Enable GPIO clock and configures the USART pins **********************/

	/* Enable the peripheral clock of GPIO Port */
	LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOC);
	/* Configure Tx Pin as : Alternate function, High Speed, Push pull, Pull up */
	LL_GPIO_SetPinMode(GPIOC, LL_GPIO_PIN_6, LL_GPIO_MODE_ALTERNATE);
	LL_GPIO_SetPinSpeed(GPIOC, LL_GPIO_PIN_6, LL_GPIO_SPEED_FREQ_HIGH);
	LL_GPIO_SetPinOutputType(GPIOC, LL_GPIO_PIN_6, LL_GPIO_OUTPUT_PUSHPULL);
	LL_GPIO_SetPinPull(GPIOC, LL_GPIO_PIN_6, LL_GPIO_PULL_UP);
	LL_GPIO_SetAFPin_0_7(GPIOC, LL_GPIO_PIN_6, LL_GPIO_AF_8);

	/* Configure Rx Pin as : Alternate function, High Speed, Push pull, Pull up */
	LL_GPIO_SetPinMode(GPIOC, LL_GPIO_PIN_7, LL_GPIO_MODE_ALTERNATE);
	LL_GPIO_SetPinSpeed(GPIOC, LL_GPIO_PIN_7, LL_GPIO_SPEED_FREQ_HIGH);
	LL_GPIO_SetPinOutputType(GPIOC, LL_GPIO_PIN_7, LL_GPIO_OUTPUT_PUSHPULL);
	LL_GPIO_SetPinPull(GPIOC, LL_GPIO_PIN_7, LL_GPIO_PULL_UP);
	LL_GPIO_SetAFPin_0_7(GPIOC, LL_GPIO_PIN_7, LL_GPIO_AF_8);

	/* (2) Enable USART6 peripheral clock and clock source ****************/
	LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART6);
	

	/* (3) Configure USART6 functional parameters ********************************/

	/* TX/RX direction */
	LL_USART_SetTransferDirection(USART6, LL_USART_DIRECTION_TX_RX);
	/* 8 data bit, 1 start bit, 1 stop bit, no parity */
	LL_USART_ConfigCharacter(USART6, LL_USART_DATAWIDTH_8B, LL_USART_PARITY_NONE, LL_USART_STOPBITS_1);
	LL_USART_SetOverSampling(USART6, LL_USART_OVERSAMPLING_16);
	LL_USART_SetHWFlowCtrl(USART6, LL_USART_HWCONTROL_NONE);
	LL_RCC_GetSystemClocksFreq(&rcc_clocks);
	LL_USART_SetBaudRate(USART6, rcc_clocks.PCLK2_Frequency, LL_USART_OVERSAMPLING_16, BaudRate); 
	
	NVIC_SetPriority(USART6_IRQn, 2);  
	NVIC_EnableIRQ(USART6_IRQn);
	LL_USART_EnableIT_IDLE(USART6);
	LL_USART_EnableIT_RXNE(USART6);
	/* (4) Enable USART6 **********************************************************/
	LL_USART_ConfigAsyncMode(USART6);
	LL_USART_Enable(USART6);
	recvLength = 0;
	memset(buffer, 0, sizeof(buffer));
	pbuffer = buffer;
	devUART6.recvFlag = false;
	devUART6.write = UART6_SendBytes;
	devUART6.read = UART6_ReadBytes;
	devUART6.print = UART6_PrintString;
}

static void UART6_SendBytes(uint8_t *pBuf, uint32_t length) {
	uint32_t i;
	for(i=0;i<length;i++) {
		LL_USART_TransmitData8(USART6, pBuf[i]);
		while(LL_USART_IsActiveFlag_TXE(USART6) == RESET);
	}
}

static void UART6_PrintString(const char *fmt, ...) {
	uint16_t i;
	va_list argptr;
	va_start(argptr, fmt);
	memset(uartShareBuffer, 0, sizeof(uartShareBuffer));
	vsprintf((char*)uartShareBuffer, fmt, argptr);
	va_end(argptr);
	for(i=0;i<strlen((char*)uartShareBuffer);i++) {
		if(uartShareBuffer[i] == '\n') {
			LL_USART_TransmitData8(USART6, '\r');
			while(LL_USART_IsActiveFlag_TXE(USART6) == RESET);
		}
		LL_USART_TransmitData8(USART6, uartShareBuffer[i]);
		while(LL_USART_IsActiveFlag_TXE(USART6) == RESET);
	}
}

static uint16_t UART6_ReadBytes(uint8_t *pBuf) {
	memcpy(pBuf, buffer, recvLength);
	devUART6.recvFlag = false;
	return recvLength;
}

static void UART6_Receive_Callback(void) {
	*pbuffer++ = LL_USART_ReceiveData8(USART6);
}

static void UART6_Idle_Callback(void) {
	recvLength = pbuffer - buffer;
	pbuffer = buffer;
	devUART6.recvFlag = true;
}

void USART6_IRQHandler(void) {
	if(LL_USART_IsActiveFlag_RXNE(USART6)) {
		LL_USART_ClearFlag_RXNE(USART6);
		UART6_Receive_Callback();
	}
	else if(LL_USART_IsActiveFlag_IDLE(USART6)) {
		LL_USART_ClearFlag_IDLE(USART6);
		UART6_Idle_Callback();
	}
}
